//基于阻塞队列的生产者消费者模型

// #ifndef __BLOCK_QUEUE_HPP__
// #define __BLOCK_QUEUE_HPP__
// #include <iostream>
// #include <string>
// #include <queue>
// #include <pthread.h>

// template<class T>
// class BlockQueue
// {
// private:
//     bool iffull()
//     {
//         return _block_queue.size() == _cap;
//     }
//     bool isempty()
//     {
//         return _block_queue.empty();
//     }
// public:
//     BlockQueue(const int cap) : _cap(cap)
//     {
//         _productor_wait_num = 0;
//         _consumer_wait_num = 0;
//         //对锁进行初始化
//         pthread_cond_init(&_product_cond, nullptr);
//         pthread_cond_init(&_consum_cond, nullptr);
//         pthread_mutex_init(&_mutex, nullptr);
//     }

//     void Enqueue(T& in)//生产者使用的接口
//     {
//         pthread_mutex_lock(&_mutex);
//         while(iffull())
//         {
//             // ⽣产线程去等待,是在临界区中休眠的！你现在还持有锁呢！！！
//             // 1. pthread_cond_wait调⽤是: a. 让调⽤线程等待 b. ⾃动释放曾经持有的_mutex锁 c. 当条件满⾜，线程唤醒，pthread_cond_wait要求线性
//             // 必须重新竞争_mutex锁，竞争成功，⽅可返回！！！
//             // 之前：安全
//             _productor_wait_num++;
//             pthread_cond_wait(&_product_cond, &_mutex);// 只要等待，必定会有唤醒，唤醒的时候，就要继续从这个位置向下运⾏！
//             _productor_wait_num--;
//             //之后：安全
//         }
//         //开始进行生产
//         // _block_queue.push(std::move(in));
//         // std::cout << in << std::endl     
//         _block_queue.push(in);

//         if(_consumer_wait_num > 0)
//             pthread_cond_signal(&_consum_cond); // pthread_cond_broadcast

//         pthread_mutex_unlock(&_mutex);  
//     }

//     void pop(T* out)//消费者用的接口：五个消费者
//     {
//         pthread_mutex_lock(&_mutex);
//         while(isempty())
//         {
//             // 消费线程去等待,是在临界区中休眠的！你现在还持有锁呢！！！
//             // 1. pthread_cond_wait调⽤是: a. 让调⽤进程等待 b. ⾃动释放曾经持有的_mutex锁
//             _consumer_wait_num++;
//             pthread_cond_wait(&_consum_cond, &_mutex);
//             _consumer_wait_num--;
//         }
//         //进行消费
//         *out = _block_queue.front();
//         _block_queue.pop();
//         // 通知⽣产者来⽣产
//         if(_productor_wait_num > 0)
//             pthread_cond_signal(&_product_cond);

//         pthread_mutex_unlock(&_mutex);
//         // pthread_cond_signal(&_product_cond);
//     }
//     ~BlockQueue()
//     {
//         pthread_mutex_destroy(&_mutex);
//         pthread_cond_destroy(&_product_cond);
//         pthread_cond_destroy(&_consum_cond);
//     }


// private:
//     std::queue<T> _block_queue; // 阻塞队列，是被整体使⽤的！！！
//     int _cap; // 总上限
//     pthread_mutex_t _mutex; // 保护_block_queue的锁
//     pthread_cond_t _product_cond; // 专⻔给⽣产者提供的条件变量
//     pthread_cond_t _consum_cond; // 专⻔给消费者提供的条件变量
//     int _productor_wait_num;
//     int _consumer_wait_num;
// };

// #endif



//基于环形队列的生产者消费者模型
#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <semaphore.h>
#include"Sem.hpp"
#include <pthread.h>

template<typename T>
class RingQueue
{
private:
    void Lock(Pthread_mutex_t &mutex)
    {
        pthread_mutex_lock(&mutex);
    }
    void Unlock(pthread_mutex_t &mutex)
    {
        pthread_mutex_unlock(&mutex);
    }

public:
    RingQueue(int cap) 
        : _ring_queue(cap),
        _cap(cap),
        _room_sem(cap),
        _data_sem(0),
        _productor_step(0),
        _consumer_step(0)
    {
        pthread_mutex_init(&_productor_mutex, nullptr);
        pthread_mutex_init(&_consumer_mutex, nullptr);
    }

    void Enqueue(const T& in)
    {
        //生产
        _room_sem.p();
        Lock(_productor_mutex);
        //一定有空间
        _ring_queue[_productor_step++] = in; // ⽣产
        _productor_step %= _cap;
        Unlock(_productor_mutex);
        _data_sem.V();
    }
    void Pop(T *out)
    {
        // 消费⾏为
        _data_sem.P();
        Lock(_consumer_mutex);
        *out = _ring_queue[_consumer_step++];
        _consumer_step %= _cap;
        Unlock(_consumer_mutex);
        _room_sem.V();
    }
    ~RingQueue()
    {
        pthread_mutex_destroy(_productor_mutex);
        pthread_mutex_destroy(_consumer_mutex);
        
    }
private:
    // 1. 环形队列
    std::vector<T> _ring_queue;
    int _cap; // 环形队列的容量上限

    // 2. ⽣产和消费的下标
    int _productor_step;
    int _consumer_step;

    // 3. 定义信号量
    sem _room_sem; // ⽣产者关⼼
    sem _data_sem; // 消费者关⼼

    // 4. 定义锁，维护多⽣产多消费之间的互斥关系
    pthread_mutex_t _productor_mutex;
    pthread_mutex_t _consumer_mutex;
};